﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using Microsoft.Xna.Framework.Content;
using System.Collections;
using Microsoft.Xna.Framework.Input;

namespace _2D
{
    /// <summary>
    /// Esta clase carga los Tiles especificados en el XML del mapa.
    /// </summary>
    public class Map
    {
        private Texture2D texture;
        private Vector2 position;
        private XmlDocument mapXML;
        private string tilesFile;
        private int[][] matrix;
        private int[][] CollisionMatrix;
        private Tile[] tiles;        
        private int _areaWidth;
        private int _areaHeight;
        public int bgWidth;
        public int bgHeight;
        public Rectangle[] Collisions;

        public int areaWidth
        {
            get
            {
                return _areaWidth;
            }            
        }
        public int areaHeight
        {
            get
            {
                return _areaHeight;
            }
        }

        public Map()
        {
        }

        public void Load(ContentManager content, string textureName, string XmlTileMap, string XmlMap, Vector2 vectorOrigen, int areaWidth, int areaHeight)
        {
            // TODO: Eliminar los parámetros que sobren en la llamada.
            _areaWidth = areaWidth;
            _areaHeight = areaHeight;

            //Cargamos el mapa.
            loadTiles(XmlTileMap);

            texture = content.Load<Texture2D>(textureName);
            mapXML = new XmlDocument();
            mapXML.Load(XmlMap);
            tilesFile = textureName;

            XmlNodeList map = mapXML.GetElementsByTagName("map");

            XmlNodeList BaseLayer =
            ((XmlElement)map[0]).GetElementsByTagName("BaseLayer");

            matrix = loadMatrix(BaseLayer);

            // Calcular las colisiones.
            XmlNodeList CollisionLayer =
            ((XmlElement)map[0]).GetElementsByTagName("CollisionLayer");            

            CollisionMatrix = loadMatrix(CollisionLayer);

            //Cargamos las colisiones:
            Collisions = new Rectangle[0];
            for (int row = 0; row < CollisionMatrix.Length; row++)
            {
                for (int col = 0; col < CollisionMatrix[row].Length; col++)
                {
                    int collisionCode = CollisionMatrix[row][col];

                    if (collisionCode == 1)
                    {
                        int newPositionInArray = Collisions.Length + 1;
                        Array.Resize(ref Collisions, newPositionInArray);
                        Rectangle rectCollisions = new Rectangle(tiles[0].tsTile.tileWidth * col, tiles[0].tsTile.tileHeight * row,
                            tiles[0].tsTile.tileWidth, tiles[0].tsTile.tileHeight);
                        Collisions[newPositionInArray - 1] = rectCollisions;
                    }                    
                }
            }

            // Calculamos el tamaño total del mapa.
            bgWidth = tiles[0].tsTile.tileWidth * matrix.Length;
            bgHeight = tiles[0].tsTile.tileHeight * matrix[0].Length;

        }

        public int[][] loadMatrix(XmlNodeList nodeList)
        {

            int[][] auxMatrix = null;

            foreach (XmlElement nodo in nodeList)  // Sólo hay uno.
            {
                string strNode = nodo.InnerText;

                strNode = strNode.Replace(Environment.NewLine, "").Replace("  ", " ");
                char[] separators = new char[1];
                separators[0] = ';';
                string[] strNodeSplit = strNode.Split(separators, StringSplitOptions.RemoveEmptyEntries);

                int row = 0;
                int col;
                auxMatrix = new int[strNodeSplit.Count()][];

                foreach (string collisionRow in strNodeSplit)
                {
                    char[] separators2 = new char[1];
                    separators2[0] = ' ';

                    string[] tilesSplit2 = collisionRow.Split(separators2, StringSplitOptions.RemoveEmptyEntries);
                    col = 0;

                    int[] aux = new int[tilesSplit2.Count()];
                    foreach (string tileColumn in tilesSplit2)
                    {

                        aux[col] = int.Parse(tileColumn);

                        col++;
                    }
                    auxMatrix[row] = aux;
                    row++;
                }
            }
            return auxMatrix;
        }


        /// <summary>
        /// Carga los datos de recorte del "tilemap".
        /// </summary>
        /// <param name="XMLFile"></param>
        private void loadTiles(string XMLFile)
        {
            XmlDocument tilemapXML = new XmlDocument();
            tilemapXML.Load(XMLFile);

            XmlNodeList tilesNodeList = tilemapXML.GetElementsByTagName("Tiles");

            XmlNodeList tileElement =
            ((XmlElement)tilesNodeList[0]).GetElementsByTagName("Tile");

            int i = 0;
            tiles = new Tile[tileElement.Count];

            foreach (XmlElement nodo in tileElement)
            {
                Tile tileAux = new Tile(int.Parse(nodo.GetElementsByTagName("X")[0].InnerText),
                    int.Parse(nodo.GetElementsByTagName("Y")[0].InnerText),
                    int.Parse(nodo.GetElementsByTagName("Height")[0].InnerText),
                    int.Parse(nodo.GetElementsByTagName("Width")[0].InnerText));

                tiles[i] = tileAux;
                i++;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="ks"></param>
        /// <returns>Devuelve true si hemos movido al cámara o false en caso contrario</returns>


        public void Draw(SpriteBatch batch, Camera2D camera)
        {
            for (int row = 0; row < matrix.Length; row++)
            {
                for (int col = 0; col < matrix[row].Length; col++)
                {
                    int tileCode = matrix[row][col];
                    position = new Vector2(col * tiles[tileCode].tsTile.tileWidth, row * tiles[tileCode].tsTile.tileHeight);

                    Rectangle visualizationArea = new Rectangle((int)camera.position.X, (int)camera.position.Y, _areaWidth, _areaHeight);
                    Rectangle currentTileRectangle = new Rectangle((int)position.X, (int)position.Y,
                                                tiles[tileCode].tsTile.tileWidth, 
                                                tiles[tileCode].tsTile.tileHeight);

                    if (currentTileRectangle.Intersects(visualizationArea))
                    {

                        int offsetW, offsetH;

                        //*********************
                        if ((currentTileRectangle.X + currentTileRectangle.Width)
                            > (visualizationArea.X + visualizationArea.Width))
                        {
                            offsetW = (visualizationArea.X + visualizationArea.Width) - (currentTileRectangle.X + currentTileRectangle.Width);
                        }
                        else
                        {
                            offsetW = 0;
                        }
                        //*********************
                        if ((currentTileRectangle.Y + currentTileRectangle.Height)
                            > (visualizationArea.Y + visualizationArea.Height))
                        {
                            offsetH = (visualizationArea.Y + visualizationArea.Height) - (currentTileRectangle.Y + currentTileRectangle.Height);
                        }
                        else
                        {
                            offsetH = 0;
                        }
                        //*********************


                        ////Dibujamos:
                        ///////////Rectangle sourcerect = new Rectangle(offsetX, offsetY, offsetW, offsetH);
                        Rectangle sourcerect = new Rectangle(tiles[tileCode].tsTile.tileX,
                            tiles[tileCode].tsTile.tileY,
                            tiles[tileCode].tsTile.tileWidth + offsetW, 
                            tiles[tileCode].tsTile.tileHeight + offsetH);

                        batch.Draw(texture, position, sourcerect, Color.White,
                            0, camera.position, 1, SpriteEffects.None, 1);
                    }
                }
            }
        }


        //public void Draw(SpriteBatch batch, Camera2D camera)
        //{
        //    for (int row = 0; row < matrix.Length; row++)
        //    {
        //        for (int col = 0; col < matrix[row].Length; col++)
        //        {
        //            int tileCode = matrix[row][col];
        //            position = new Vector2(col * tiles[tileCode].tsTile.tileWidth, row * tiles[tileCode].tsTile.tileHeight);

        //            Rectangle sourcerect = new Rectangle(tiles[tileCode].tsTile.tileX, tiles[tileCode].tsTile.tileY,
        //                tiles[tileCode].tsTile.tileWidth, tiles[tileCode].tsTile.tileHeight);


        //            batch.Draw(texture, position, sourcerect, Color.White,
        //                0, camera.position, 1, SpriteEffects.None, 1);
        //        }
        //    }
        //}
    }
}

